# -*- coding: utf-8 -*-
#
# Copyright 2009 Vanderbilt University
# 
# Licensed under the Apache License, Version 2.0 (the "License"); 
# you may not use this file except in compliance with the License. 
# You may obtain a copy of the License at 
# 
#     http://www.apache.org/licenses/LICENSE-2.0 
# 
# Unless required by applicable law or agreed to in writing, software 
# distributed under the License is distributed on an "AS IS" BASIS, 
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
# See the License for the specific language governing permissions and 
# limitations under the License. 

"""

.. moduleauthor:: John Paulett <john.paulett -at- vanderbilt.edu>
"""

import logging
import operator
import numpy

from sqlalchemy import create_engine, Table, Column, Integer, Boolean, String, ForeignKey, Text
from sqlalchemy.orm import relation, backref, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

from BeautifulSoup import BeautifulStoneSoup

from urlgrabber import urlread

import hornet.network
from hornet.plugin import Plugin
from hornet.file import write_csv

logger = logging.getLogger(__name__)

#engine = create_engine('sqlite:///:memory:')#, echo=True
engine = create_engine('sqlite:///db.txt')
Base = declarative_base()
metadata = Base.metadata 

# association tables
person_paper = Table('person_paper', metadata,
    Column('paper_id', Integer, ForeignKey('papers.pmid')),
    Column('person_id', Integer, ForeignKey('people.id'))
)
term_paper = Table('term_paper', metadata,
    Column('term_id', Integer, ForeignKey('terms.id')),
    Column('paper_id', Integer, ForeignKey('papers.pmid'))
)

class Person(Base):
    __tablename__ = 'people'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    internal = Column(Boolean, default=False)

    def __init__(self, name):
        self.name = name
    
    def __repr__(self):
       return "<Person('%s')>" % (self.name)

class Term(Base):
    __tablename__ = 'terms'

    id = Column(Integer, primary_key=True)
    title = Column(String)

    def __init__(self, title):
        self.title = title

    def __repr__(self):
       return "<Term('%s')>" % (self.title)
   
class Paper(Base):
    __tablename__ = 'papers'

    pmid = Column(Integer, primary_key=True)
    title = Column(String)
    journal = Column(String)
    people = relation('Person', secondary=person_paper, backref='papers')
    terms = relation('Term', secondary=term_paper, backref='papers')

    def __init__(self, pmid, title, journal):
        self.pmid = pmid
        self.title = title
        self.journal = journal

    def __repr__(self):
       return "<Paper('%s','%s','%s')>" % (self.pmid, self.title, self.journal)

metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()


def run():
    for name in ['Malin Bradley']:
        process_person(name)

def process_person(person_name):
    
    for article_xml in lookup_papers(person_name):
        # add the basics of the paper
        title = get_contents(article_xml, 'articletitle')
        journal = get_contents(article_xml, 'medlineta')
        pmid = get_contents(article_xml, 'pmid')
        paper = Paper(pmid, title, journal)
        logger.debug('Adding paper: %s' % title)
        
        # add the authors
        for author_xml in article_xml.findAll('author'):
            name = '%s %s' % (get_contents(author_xml, 'lastname'), 
                              get_contents(author_xml, 'forename'))
            person = session.query(Person).filter_by(name=name).first()
            if person is None:
                person = Person(name)
                logger.debug('Created new author: %s' % name)
            paper.people.append(person)
            
        # add all the MeSH terms 
        for term_xml in article_xml.findAll('descriptorname'):
            term_title = term_xml.contents[0]
            term = session.query(Term).filter_by(title=term_title).first()
            if term is None:
                term = Term(term_title)
                logger.debug('Created new term: %s' % term_title)
                # !!! do I need to manually insert?
            paper.terms.append(term)
        session.add(paper)
    session.commit()

def lookup_papers(name):
    url = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=xml&retmode=xml&db=pubmed&query_key=%s&WebEnv=%s' % env_query(name)
    xml = get_xml_url(url)
    logger.debug('Finished lookup query for %s' % name)
    return xml.findAll('pubmedarticle')

def env_query(name):
    url  = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&usehistory=y&field=auth&term=%s' % name 
    xml = get_xml_url(url)
    logger.debug('Finished env_query for %s' % name)
    return get_contents(xml, 'querykey'), get_contents(xml, 'webenv')

def get_xml_url(url):
    """Connect to *url* and parse the response into a BeautifulSoup object.
    """
    response = urlread(url)
    return BeautifulStoneSoup(response)

def get_contents(xml, id):
    """Simple accessor method for returning the contents of an xml tag 
    specified by *id* within the xml document *xml*.
    """
    return xml.find(id).contents[0]

if __name__ == '__main__':
    run()